package com.astar.framework.config.properties;

import com.astar.common.annotation.Anonymous;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
import org.apache.commons.lang3.RegExUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

/**
 * 设置Anonymous注解允许匿名访问的url
 *
 * @author astar
 */
@Configuration
public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware {
  private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
  public String ASTERISK = "*";
  private ApplicationContext applicationContext;
  private List<String> urls = new ArrayList<>();

  @Override
  public void afterPropertiesSet() {
    RequestMappingHandlerMapping mapping =
        applicationContext.getBean(RequestMappingHandlerMapping.class);
    Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();

    map.keySet()
        .forEach(
            info -> {
              HandlerMethod handlerMethod = map.get(info);
              if (info.getPatternsCondition() != null) {
                // 获取方法上边的注解 替代path variable 为 *
                Anonymous method =
                    AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
                Optional.ofNullable(method)
                    .ifPresent(
                        anonymous ->
                            Objects.requireNonNull(info.getPatternsCondition().getPatterns())
                                .forEach(
                                    url ->
                                        urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));

                // 获取类上边的注解, 替代path variable 为 *
                Anonymous controller =
                    AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
                Optional.ofNullable(controller)
                    .ifPresent(
                        anonymous ->
                            Objects.requireNonNull(info.getPatternsCondition().getPatterns())
                                .forEach(
                                    url ->
                                        urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
              }
            });
  }

  @Override
  public void setApplicationContext(ApplicationContext context) throws BeansException {
    this.applicationContext = context;
  }

  public List<String> getUrls() {
    return urls;
  }

  public void setUrls(List<String> urls) {
    this.urls = urls;
  }
}
